package com.battcn.config;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import com.alibaba.fastjson.JSON;
import com.battcn.platform.service.pub.OperateService;
import com.battcn.platform.shiro.MyRealm;
import com.battcn.platform.shiro.credentials.RetryLimitHashedCredentialsMatcher;
import com.google.common.collect.Maps;

/**
 * shiro配置类
 * 
 * @author yanglei
 *
 */
@Configuration
@EnableCaching
@Lazy(false)
public class ShiroConfig {
	private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
	/*<bean id="credentialsMatcher"
			class="com.battcn.platform.shiro.credentials.RetryLimitHashedCredentialsMatcher">
			<!-- hashAlgorithmName必须的，没有默认值。可以有MD5或者SHA-1，如果对密码安全有更高要求可以用SHA-256或者更高。 
				这里使用MD5 storedCredentialsHexEncoded默认是true，此时用的是密码加密用的是Hex编码；false时用Base64编码 
				hashIterations迭代次数，默认值是1。 -->
			<constructor-arg ref="cacheManager" />
			<property name="hashAlgorithmName" value="md5" />
			<property name="hashIterations" value="2" />
			<property name="storedCredentialsHexEncoded" value="true" />
		</bean>*/
	// 凭证匹配器
		@Bean(name = "credentialsMatcher")
		public CredentialsMatcher credentialsMatcher(CacheManager cacheManager) {
			logger.debug("2. Shiro 凭证匹配器");
			RetryLimitHashedCredentialsMatcher a = new RetryLimitHashedCredentialsMatcher(
					cacheManager);
			a.setHashAlgorithmName("md5");
			a.setHashIterations(2);
			a.setStoredCredentialsHexEncoded(true);
			return a;
		}
	@Bean
	public EhCacheManager getEhCacheManager() {
		System.out.println("--------------EhCacheManager-------------");
		EhCacheManager em = new EhCacheManager();
		em.setCacheManagerConfigFile("classpath:ehcache.xml");
		return em;
	}

	@Bean(name = "AuthRealm")
	public MyRealm AuthRealm(EhCacheManager cacheManager,CredentialsMatcher credentialsMatcher) {
		System.out.println("--------------AuthRealm-------------");
		MyRealm realm = new MyRealm();
		realm.setCacheManager(cacheManager);
		realm.setCredentialsMatcher(credentialsMatcher);
		return realm;
	}

	@Bean(name = "lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
		System.out.println("--------------LifecycleBeanPostProcessor-------------");
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
		System.out.println("--------------DefaultAdvisorAutoProxyCreator-------------");
		DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
		daap.setProxyTargetClass(true);
		return daap;
	}

	@Bean(name = "securityManager")
	public DefaultWebSecurityManager getDefaultWebSecurityManager(MyRealm AuthRealm) {
		System.out.println("--------------securityManager-------------");
		DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
		dwsm.setRealm(AuthRealm);
		// <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
		dwsm.setCacheManager(getEhCacheManager());
		return dwsm;
	}

	@Bean
	public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(
			DefaultWebSecurityManager securityManager) {
		System.out.println("--------------AuthorizationAttributeSourceAdvisor-------------");
		AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
		aasa.setSecurityManager(securityManager);
		return aasa;
	}

	/**
	 * 加载shiroFilter权限控制规则（从数据库读取然后配置）
	 */
	private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean,@Autowired OperateService service) {
		System.out.println("--------------loadShiroFilterChain-------------");
		/////////////////////// 下面这些规则配置最好配置到配置文件中 ///////////////////////
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		filterChainDefinitionMap.put("/static/**", "anon");
		filterChainDefinitionMap.put("/logining", "anon");
		filterChainDefinitionMap.put("/install", "anon");
		filterChainDefinitionMap.put("/404.jsp", "anon");
		filterChainDefinitionMap.put("/error.jsp", "anon");
		 //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
		// anon：它对应的过滤器里面是空的,什么都没做
		logger.info("##################从数据库读取权限规则，加载到shiroFilter中##################");
		Map<String, String> permissions = Maps.newLinkedHashMap();
		
		service.listShiroPermissions(null).stream().forEach(pms -> {
			logger.info("perms[" + pms.getPerms() + "]");
			permissions.put(pms.getPath(), "authc,perms[" + pms.getPerms() + "]");
		});
		filterChainDefinitionMap.putAll(permissions);
		filterChainDefinitionMap.put("/**", "authc");
		logger.debug("[拦截链] - [{}]", JSON.toJSONString(filterChainDefinitionMap));
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
	}

	/**
	 * ShiroFilter<br/>
	 * 注意这里参数中的 StudentService 和 IScoreDao 只是一个例子，因为我们在这里可以用这样的方式获取到相关访问数据库的对象，
	 * 然后读取数据库相关配置，配置到 shiroFilterFactoryBean 的访问规则中。实际项目中，请使用自己的Service来处理业务逻辑。
	 *
	 * @param AuthRealm
	 * @param stuService
	 * @param scoreDao
	 * @return
	 * @author SHANHY
	 * @create 2016年1月14日
	 */
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager,
			OperateService service) {
		System.out.println("--------------shiroFilter-------------");
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 必须设置 SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		shiroFilterFactoryBean.setLoginUrl("/login");
		// 登录成功后要跳转的连接
		shiroFilterFactoryBean.setSuccessUrl("/index");
		shiroFilterFactoryBean.setUnauthorizedUrl("/denied");
		loadShiroFilterChain(shiroFilterFactoryBean, service);
		return shiroFilterFactoryBean;
	}
}
